#!/usr/bin/python --

## CpuEntity.py
##
## Dru Nelson <dru@egroups.com>
## 7-11-99

'''
CpuEntity.py -- objects for doing my QOS measurments

This one monitors the CPU load of a machine

'''  # '

import os,sys,string,commands,time
import Entity


class CpuEntity (Entity.Entity):
    def __init__(self, host, dict):
        Entity.Entity.__init__(self, host, dict)
        self.module         = 'CpuEntity'
        self.moduleversion  = '1.0'
        self.fields  = ['status:c', 'uptime:f', 'load:f', 'trigger:f', 'error:s']

        self.subEntities    = { 'cpu0' : '', }

        self.triggers       = dict['triggers']

        self.currentLoad    = 0.0
        self.uptime         = 0.0

        # Set the time period to every 5 minutes
        try:
            self.timePeriod = dict['timePeriod']
        except KeyError:
            self.timePeriod = 2


        self.propagateNotify(self.triggers)

    def doCollectDataWin32(self):
        import win32pdh
        import win32pdhquery

        try:
            han = win32pdh.OpenQuery()
            thepath = win32pdh.MakeCounterPath((None, "Processor", "_Total", None, 0, "% Processor Time"))
            counter_handle = win32pdh.AddCounter(han, thepath)
            win32pdh.CollectQueryData(han) # do the deed
            win32pdh.CollectQueryData(han) # needs to be done a few times to flush bogus values
            self.currentLoad = float(win32pdh.GetFormattedCounterValue(counter_handle, win32pdh.PDH_FMT_LONG)[1])
            win32pdh.CloseQuery(han)
        except:
            print "Error collecting CPU usage data"
            self.currentLoad = 0
            raise

        # next up:  System\System Up Time
        try:
            han = win32pdh.OpenQuery()
            thepath = win32pdh.MakeCounterPath((None, "System", None, None, 0, "System Up Time"))
            counter_handle = win32pdh.AddCounter(han, thepath)
            win32pdh.CollectQueryData(han) # do the deed
            self.uptime = float(win32pdh.GetFormattedCounterValue(counter_handle, win32pdh.PDH_FMT_LONG)[1])
            win32pdh.CloseQuery(han)
        except:
            print "Error collecting CPU usage data"
            self.uptime = 0
            raise

        # self.uptime = self.uptime * 60

    def doCollectData(self):

        # Get the 5 min load average
        if 'linux2' == sys.platform or 'linux-i386' == sys.platform:
            f = open('/proc/loadavg', 'r')
            data = f.read()
            data = data[:-1]          # Remove the newline
            f.close()
            (load1min, load5min, load15min, nr_runningNr_tasks, last_pid) = string.split( data, " ")

            f = open('/proc/uptime', 'r')
            data = f.read()
            data = data[:-1]          # Remove the newline
            f.close()
            (uptime, idletime) = string.split( data, " ")
            self.uptime      = float(uptime)
            self.currentLoad = float(load5min)
            return

        elif 'freebsd' == sys.platform[:7]:
            data = commands.getstatusoutput('/sbin/sysctl vm.loadavg')
            # want the 4th argument of : (0, 'vm.loadavg: { 0.17 0.10 0.02 }')
            (title, bracket, load1min, load5min, load10min) = string.split(data[1], " ", 4)
            self.currentLoad = float(load5min)
            # kern.boottime: { sec = 941599162, usec = 949487 } Tue Nov  2 19:19:22 1999
            data = commands.getstatusoutput('/sbin/sysctl kern.boottime')
            (title, bracket, blah, blah2, starttime, rest) = string.split(data[1], " ", 5)
            starttime = string.translate(starttime, string.maketrans(',', ' '))
            self.uptime = float(time.time() - string.atof(starttime))
            return

        elif 'sunos5' == sys.platform:
            # Solaris - we can get the uptime, but we must punt on the uptime
            data = commands.getstatusoutput('/usr/bin/uptime')
            if data[0] == 0:
                (junk, loads) = string.split(data[1], ": ")
                (load1min, load5min, load10min) = string.split(loads, ", ")
                self.currentLoad = string.atof(load5min)

                # Now get the mtime of /proc/0
                startTime = os.stat('/proc/0')[8]
                self.uptime = time.time() - startTime
                return

        elif 'darwin' == sys.platform[:6] or 'openbsd' == sys.platform[:7] or 'netbsd' == sys.platform[:6]:
            data = commands.getstatusoutput('/sbin/sysctl -n vm.loadavg')
            # want the 3th argument of : (0, '0.17 0.10 0.02')
            (load1min, load5min, load10min) = string.split(data[1], " ", 2)
            self.currentLoad = float(load5min)
            # -n on this sysctl returns the unix timestamp -- handy.
            (status, output) = commands.getstatusoutput('/sbin/sysctl -n kern.boottime')
            self.uptime = float(time.time() - int(output))
            return
        elif 'win32' == sys.platform:
            self.doCollectDataWin32()
            return

        # Indicate an error
        self.uptime      = 0.0
        self.currentLoad = 99.0
        return


    def doRealCheck(self):

        # This 'for' loop is useless, but the contents
        # of the loop are good
        for se in self.subEntities.keys():

            # Check against triggers
            print 'load',self.currentLoad
            print 'uptime',self.uptime
            fire, trigger = self.triggerNumberCheck(self.triggers, self.currentLoad)

            # Check if the machine just rebooted
            if self.uptime < 300.00:
                self.setState(se, 'R', "machine rebooted  [uptime %s secs]" %self.uptime, '%0.2f %0.2f %0.2f' % (self.uptime, self.currentLoad, 0), trigger)


            if fire == 0:
                self.setState(se, 'G', "load avg normal [%s]" %self.currentLoad, '%0.2f %0.2f %0.2f' % (self.uptime, self.currentLoad, float(trigger['trigger'])), trigger)
            else:
                self.setState(se, 'F', "load avg high [%s]" %self.currentLoad, '%0.2f %0.2f %0.2f' % (self.uptime, self.currentLoad, float(trigger['trigger'])), trigger)